/******************************************************
 * Copyright (c) 2012, LIJUN All rights reserved *
 ******************************************************/

/**
 * Animation接口
 * @author carlli
 * @encode utf-8
 * @version 1.0
 * @data 2012.9.24
 * @modify
 * -------------------------------------------------------------------
 * 
 * -------------------------------------------------------------------
 * @usage
 * -------------------------------------------------------------------
 *
 * -------------------------------------------------------------------
 */

Smart.define("animation", function(S){
    var G_ANIMATION_MAP = null;   // Animation实例MAP
    var G_CLICK_EVENT = (("ontouchend" in window) ? "touchend" : "click"); //默认点击事件
    
    var _Tween = S.Tween; //Tween实例
    
    /**
     * 获取Animation实例
     * @param String name 实例名称
     * @param Boolean create 在不存在时是否创建新的一个新的实例
     * @return Animation animation
     */
    function GetAnimation(name, create){
        var instance = null;
        G_ANIMATION_MAP = G_ANIMATION_MAP || {};
        if(true === create){
            if(!G_ANIMATION_MAP[name]){
                instance = G_ANIMATION_MAP[name] = new _Animation(name);
            }else{
                instance = G_ANIMATION_MAP[name];
            }
        }else{
            instance = (G_ANIMATION_MAP[name] || null);
        }
        return instance;
    };
    
    /**
     * 动画效果（构造函数）
     * @param String name
     */
    var _Animation = function(name){
        this.name = name;       // 名称，唯一标识
        this.timer = null;      // 定时器
        this.delay = 0;         // 延时执行
        this.Types = {
            "IN" : "easeIn",        //in
            "OUT" : "easeOut",      //out
            "IN_OUT" : "easeInOut"  //in-out
        };

        this.attr = { // 动画属性配置
            begin : 0,   //开始位置
            speed : 0,   //速度
            change : 0,  //改变区间量
            duration : 0 //持续时间
        };
        //--------------------------------------------
        this.on = {
            onstart : null,      //开始时的回调，{Function callback, Array args, Object context}
            onstop : null,       //停止时的回调，{Function callback, Array args, Object context}
            oniteration : null,  //迭代调用回调，{Function callback, Array args, Object context}
            onprogress : null,   //处理过程中的回调，{Function callback, Array args, Object context}
            onbefore : null,     //开始前的回调{Function callback, Array args, Object context}
            onbeforecheck : null //开始前校验的回调{Function callback, Array args, Object context}
        };
    };
    _Animation.prototype = {
        /**
         * 执行回调函数
         * @param String type 类型
         * @param Array args 消息
         * @return * result 返回值
         */
        execCallback : function(type, args){
            var o = this.get(type);
            var m = args || [];
            var a = [].concat(m);
            var result = undefined;

            if(o && o.callback){
                a = a.concat(o.args||[]);
                if(true === o.returnValue){
                    result = o.callback.apply((o.context||this), a);
                }else{
                    o.callback.apply((o.context||this), a);
                }
            }
            m = null; a = null;

            return result;
        },
        /**
         * 设置回调
         * @param String type 类型
         * @param Function callback 回调
         * @param Array args 参数
         * @param Object context 上下文
         */
        set : function(type, callback, args, context){
            var key = "on" + type;
            var rvs = "|beforecheck|";

            if(key in this.on){
                if(callback && (callback instanceof Function) && callback.apply){
                    this.on[key] = {
                        "callback" : callback,
                        "args" : args || [],
                        "context" : context || this,
                        "returnValue" : (rvs.indexOf("|"+type+"|") != -1)
                    };
                }else{
                    this.on[key] = null;
                }
            }
        },
        /**
         * 移除回调
         * @param String type 类型
         */
        remove : function(type){
            this.on["on" + type] = null;
        },
        /**
         * 获取回调
         * @param String type 类型
         * @return Object on
         */
        get : function(type){
            var key = "on" + type;
            var o = this.on;

            if(key in o){
                return o[key];
            }

            return null;
        },
        /**
         * 清除所有回调
         */
        clear : function(){
            for(var key in this.on){
                if(this.on.hasOwnProperty(key)){
                    this.remove(key.substr(2));
                }
            }
        },
        /**
         * 运行动画
         * @param Node node html节点
         * @param Function ease 缓存方法
         * @param String property CSS属性
         * @param int speed 速度
         * @param int begin 起始位置
         * @param int change 区间改变量（结束位置 - 起始位置）
         * @param int duration 持续的时间
         */
        run : function(node, ease, property, speed, begin, change, duration){
            var animation = this;
            var time = 0;

            animation.execCallback("start");
            animation.timer = setTimeout(function(){
                var shift = ease(time, begin, change, duration);

                animation.execCallback("progress", [shift]);
                node.style[property] = shift + "px";

                if(time < duration){
                    animation.timer = setTimeout(arguments.callee, speed);
                }else{
                    animation.stop();
                }
                time++;
            }, speed);
        },
        /**
         * 设置动画起始位置
         * @param int begin
         */
        setAnimationBegin : function(begin){
            this.attr["begin"] = begin;
        },
        /**
         * 设置动画速度
         * @param int speed
         */
        setAnimationSpeed : function(speed){
            this.attr["speed"] = speed;
        },
        /**
         * 设置动画位置变长
         * @param int change
         */
        setAnimationChange : function(change){
            this.attr["change"] = change;
        },
        /**
         * 设置动画持续时间
         * @param int duration
         */
        setAnimationDuration : function(duration){
            this.attr["duration"] = duration;
        },
        /**
         * JS自定义动画开始
         * @param String tweenName tween类型名称
         * @param String type 类型
         * @param String selector CSS选择器
         * @param String property CSS属性
         * @param int speed 速度
         * @param int begin 起始位置
         * @param int change 区间改变量（结束位置 - 起始位置）
         * @param int duration 持续的时间
         * @return Boolean true/false
         */
        start : function(tweenName, type, selector, property, speed, begin, change, duration){
            var _tn = tweenName || "Sine";
            var _t = type || "easeInOut";
            var ease = _Tween[_tn][_t];//(this[type] || this.easeInOut);
            var node = S.Node.one(selector);

            this.setAnimationBegin(begin);
            this.setAnimationSpeed(speed);
            this.setAnimationChange(change);
            this.setAnimationDuration(duration);

            this.execCallback("before", [node]);

            if(ease && node){
                var check = this.get("beforecheck");
                var attr = this.attr;

                if((null == check ||  //没有设置beforecheck
                    (null != check && true !== check.returnValue) || //没有设置returnValue属性或returnValue属性不为true
                        (null != check && this.execCallback("beforecheck", [node])) //有设置beforecheck并且条件为真
                )){
                    this.run(node, ease, property, attr["speed"], attr["begin"], attr["change"], attr["duration"]);
                    return true;
                }
            }
            return false;
        },
        /**
         * JS自定义动画停上
         */
        stop : function(){
            if(null != this.timer){
                clearTimeout(this.timer);
                this.timer = null;
            }
            this.execCallback("stop");
        },
        /**
         * JS自定义动画是否已经停止
         * @return Boolean true/false
         */
        stopped : function(){
            return (null == this.timer);
        },
        /**
         * 调用JS自定义动画
         * @param Node|String n 节点或CSS选择符
         * @return Boolean true/false
         */
        call : function(n){
            var node = S.Node.one(n);
            
            var tweenName = node.getAttribute("data-tween") || "Sine";
            var type = this.Types[node.getAttribute("data-type") || "IN_OUT"];
            var selector = node.getAttribute("data-selector");
            var property = node.getAttribute("data-property") || "marginLeft";
            var speed = parseFloat(node.getAttribute("data-speed")||0, 10);
            var begin = parseFloat(node.getAttribute("data-begin")||0, 10);
            var change = parseFloat(node.getAttribute("data-change")||0, 10);
            var duration = parseFloat(node.getAttribute("data-duration")||0, 10);
            var offset = parseFloat(node.getAttribute("data-offset")||0, 10);

            return this.start(tweenName, type, selector, property, speed, begin, change, offset);
        },
        /**
         * 绑定自定义动画事件回调
         * @param Event e 事件
         */
        bindStartHandler : function(e){
            S.Event.preventDefault();
            S.Event.stopPropagation();
            
            var instance = GetAnimation(this.getAttribute("data-animation"));

            instance.call(this);
        },
        /**
         * 阻止点击事件默认行为
         * @param Event e
         */
        preventClick : function(e){
            S.Event.preventDefault();
            S.Event.stopPropagation();
        },
        /**
         * 绑定自定义动画
         * <tag data-animation="string" data-animation-event="type" data-tween="Sine" data-type="IN_OUT" data-selector="selector" data-property="property" data-speed="1" data-begin="0" data-change="1" data-duration="1" data-offset="1"></tag>
         * data-tween := string @see tween.js
         * data-animation := string Animation的name，程序自动设置
         * data-type := IN|OUT|IN_OUT 效果
         * data-selector := selector CSS选择符（目标节点）
         * data-property := perperty CSS属性值
         * data-speed := 0 速度
         * data-begin := 0 起始位置
         * data-change := 0 改变位置
         * data-duration := 0 持续时间
         * data-offset := 0 duration偏差值（相对iOS）
         * data-animation-event := event 事件类型
         *
         * @param String selector CSS选择符
         */
        bindStart : function(selector){
            var node = S.Node.one(selector);
            var type = G_CLICK_EVENT;

            if(null != node){
                type  = node.getAttribute("data-animation-event") || type;
                node.setAttribute("data-animation", this.name);
                S.Event.on(node, type, this.bindStartHandler, false);

                if("click" != type){
                    S.Event.on(node, "click", this.preventClick, false);
                }
            }
        },
        /**
         * CSS动画
         * @param String selector CSS选择器
         * @param String newClassName 目标class
         * @param Object styles 样式集
         */
        css : function(selector, newClassName, styles){
            var node = S.Node.one(selector);
            var ncn = newClassName || "";
            var rcn = styles || null;

            if(null != node){
                AddClass(node, ncn);

                for(var p in styles){
                    if(styles.hasOwnProperty(p)){
                        node.style[p] = styles[p];
                    }
                }
            }
            node = null;
        },
        /**
         * 开始事件回调
         * @param Event e
         */
        animationStartHandler : function(e){
            var instance = GetAnimation(this.getAttribute("data-animation"));
            instance.execCallback("start", [e]);

            S.Event.remove(this, "webkitAnimationStart", arguments.callee, true);
        },
        /**
         * 结束事件回调
         * @param Event e
         */
        animationEndHandler : function(e){
            var instance = GetAnimation(this.getAttribute("data-animation"));
            instance.execCallback("stop", [e]);

            S.Event.remove(this, "webkitAnimationEnd", arguments.callee, true);
        },
        /**
         * 执行迭代事件回调
         * @param Event e
         */
        animationIterationHandler : function(e){
            var instance = GetAnimation(this.getAttribute("data-animation"));
            instance.execCallback("iteration", [e]);

            S.Event.remove(this, "webkitAnimationIteration", arguments.callee, true);
        },
        /**
         * CSS动画(animation)
         * <tag data-animation="string"></tag>
         * data-animation := string Animation的name，程序自动设置
         *
         * @param String|Node selector CSS选择器|节点
         * @param String newClassName 目标class
         * @param Object styles 样式集
         */
        animation : function(selector, newClassName, styles){
            var node = S.Node.one(selector);

            this.execCallback("before", [node]);

            if(null != node){
                node.setAttribute("data-animation", this.name);

                var check = this.get("beforecheck");
                if((null == check ||  //没有设置beforecheck
                    (null != check && true !== check.returnValue) || //没有设置returnValue属性或returnValue属性不为true
                        (null != check && this.execCallback("beforecheck", [node])) //有设置beforecheck并且条件为真
                )){
                    S.Event.on(node, "webkitAnimationStart", this.animationStartHandler, true);
                    S.Event.on(node, "webkitAnimationEnd", this.animationEndHandler, true);
                    S.Event.on(node, "webkitAnimationIteration", this.animationIterationHandler, true);

                    this.css(selector, newClassName, styles);
                }
            }
        },
        /**
         * 结束事件回调
         * @param Event e
         */
        transitionEndHandler : function(e){
            var instance = GetAnimation(this.getAttribute("data-animation"));
            instance.execCallback("stop", [e]);

            S.Event.remove(this, "webkitTransitionEnd", arguments.callee, true);
        },
        /**
         * CSS动画(transition)
         * <tag data-animation="string"></tag>
         * data-animation := string Animation的name，程序自动设置
         *
         * @param String|Node selector CSS选择器|节点
         * @param String newClassName 目标class
         * @param Object styles 样式集
         */
        transition : function(selector, newClassName, styles){
            var node = S.Node.one(selector);

            this.execCallback("before", [node]);

            if(null != node){
                node.setAttribute("data-animation", this.name);
                var check = this.get("beforecheck");

                if((null == check ||  //没有设置beforecheck
                    (null != check && true !== check.returnValue) || //没有设置returnValue属性或returnValue属性不为true
                        (null != check && check.returnValue && this.execCallback("beforecheck", [node])) //有设置beforecheck并且条件为真
                )){
                    S.Event.on(node, "webkitTransitionEnd", this.transitionEndHandler, true);

                    this.execCallback("start");
                    this.css(selector, newClassName, styles);
                }
            }
        },
        /**
         * 销毁
         */
        destory : function(){
            G_ANIMATION_MAP[this.name] = null;
        }
    }; // end _Animation
    
    var _o = {
        /**
         * 动画效果
         * @see _Animation
         */
        "newInstance" : function(name){
            var instance = null;

            if(!name || typeof(name) != "string"){
                throw new Error("Illegal parameter! Smart.Animation.newInstance(name)::name = " + name);
            }else{
                instance = GetAnimation(name, true);

                //方法注册
                return {
                    // 类弄[IN/OUT]
                    "Types" : instance.Types,
                    /**
                     * 设置回调
                     * @see _Animation.set(type, callback, args, context)
                     */
                    "set" : function(type, callback, args, context){instance.set(type, callback, args, context);},
                    /**
                     * 获取回调
                     * @see _Animation.get(type)
                     */
                    "get" : function(type){return instance.get(type);},
                    /**
                     * 移除回调
                     * @see _Animation.remove(type)
                     */
                    "remove" : function(type){instance.remove(type);},
                    /**
                     * 清除所有回调
                     * @see _Animation.clear()
                     */
                    "clear" : function(){instance.clear();},
                    /**
                     * 设置动画起始位置
                     * @see _Animation.setAnimationBegin(begin)
                     */
                    "setAnimationBegin" : function(begin){instance.setAnimationBegin(begin);},
                    /**
                     * 设置动画速度
                     * @see _Animation.setAnimationSpeed(speed)
                     */
                    "setAnimationSpeed" : function(speed){instance.setAnimationSpeed(speed);},
                    /**
                     * 设置动画位置变长
                     * @see _Animation.setAnimationChange(change)
                     */
                    "setAnimationChange" : function(change){instance.setAnimationChange(change);},
                    /**
                     * 设置动画持续时间
                     * @see _Animation.setAnimationDuration(duration)
                     */
                    "setAnimationDuration" : function(duration){instance.setAnimationDuration(duration);},
                    /**
                     * JS自定义动画开始
                     * @see _Animation.start(tweenName, type, selector, property, speed, begin, change, duration)
                     */
                    "start" : function(tweenName, type, selector, property, speed, begin, change, duration){return instance.start(tweenName, type, selector, property, speed, begin, change, duration);},
                    /**
                     * 调用JS自定义动画
                     * @see _Animation.call(n)
                     */
                    "call" : function(n){return instance.call(n)},
                    /**
                     * 绑定自定义动画
                     * @see _Animation.bindStart(selector)
                     */
                    "bindStart" : function(selector){instance.bindStart(selector);},
                    /**
                     * JS自定义动画停上
                     * @see _Animation.stop()
                     */
                    "stop" : function(){instance.stop();},
                    /**
                     * JS自定义动画是否已经停止
                     * @see _Animation.stopped()
                     */
                    "stopped" : function(){instance.stopped();},
                    /**
                     * CSS动画(animation)
                     * @see _Animation.animation(selector, newClassName, styles)
                     */
                    "animation" : function(selector, newClassName, styles){instance.animation(selector, newClassName, styles);},
                    /**
                     * CSS动画(transition)
                     * @see _Animation.transition(selector, newClassName, styles)
                     */
                    "transition" : function(selector, newClassName, styles){instance.transition(selector, newClassName, styles);},
                    /**
                     * 销毁Animation实例
                     * @see _Animation.destory()
                     */
                    "destory" : function(){instance.destory();}
                };
            }
        }
    };
    
    S.source("Animation", _o);
    
}); 